﻿using KCommon;
using KeyboardArg;
using Mp3Player;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace KWindow.KPageCore
{
    internal static class CommonService
    {
        #region static Fields and Functions    
        public static readonly string KeyboardManager = "SoftKeyBoardManager";

        public static readonly string KeyboardClass = "KeyboardManager.FormManager";
        static CommonService()
        {
            CreatSpeaker();
        }

        public static void CloseKeyBoardManager(IntPtr hWnd)
        {
            KeyBoardArgs arg = new KeyBoardArgs();
            arg.SenderName = "";
            arg.PassageType = SendMessageType.Exit;
            arg.SenderHandle = hWnd;
            arg.MsgReceiver = hWnd;
            string parm = JsonHandler.ConvertToJsonString(arg).Replace('"', '@');
            SendMessageToKB(hWnd, parm);
        }

        public static void SendMessageToKB(IntPtr windowHandle, string strMessage)
        {
            IntPtr[] hWndArray = GetKeyBoardManagerMainWnd();
            if (hWndArray.Length == 0)
            {
                MessageBox.Show("未能启动指定键盘!");
                return;
            }
            foreach (IntPtr hWnd in hWndArray)
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(strMessage);
                COPYDATASTRUCT_INTPTR cds = new COPYDATASTRUCT_INTPTR();
                cds.cbData = data.Length;
                cds.dwData = windowHandle;
                cds.lpData = Marshal.AllocHGlobal(data.Length);
                Marshal.Copy(data, 0, cds.lpData, data.Length);
                int nRet = Windows.SendMessage(hWnd, (int)MessageType.WM_COPYDATA, 0, ref cds);
                cds.Free();
            }
        }

        public static IntPtr[] GetKeyBoardManagerMainWnd()
        {
            return SearchWindow.Search(KeyboardManager, KeyboardClass);
        }

        /// <summary>
        /// 语音播放执行者
        /// </summary>
        private static Speaker _speaker = null;

        public static void CreatSpeaker()
        {
            _speaker = new Speaker();
        }

        public static string GetAssemblyDirectory(Type type)
        {
            Assembly ass = type.Assembly;
            string directory = Path.GetDirectoryName(ass.CodeBase);
            if(directory.StartsWith("file:\\"))
            {
                directory = directory.Substring(6);
            }
            return directory;
        }

        public static void Speak(PageControlBase page, string fileName)
        {
            //StackFrame frame = new StackFrame(1);
            //var method = frame.GetMethod();
            Type type = page.GetType();
            string dir = GetAssemblyDirectory(type);
            _speaker.VoiceDirectory = $"{dir}\\Voice\\{page.LanguageCode}";
            _speaker.OnSpeaking(fileName);
        }

        public static void Speak(PageControlBase page, List<string> listFiles)
        {
            //StackFrame frame = new StackFrame(1);
            //var method = frame.GetMethod();
            Type type = page.GetType();
            string dir = GetAssemblyDirectory(type);
            _speaker.VoiceDirectory = $"{dir}\\Voice\\{page.LanguageCode}";
            _speaker.AddList(listFiles);
        }

        public static void SpeakAsync(PageControlBase page, string fileName)
        {
            //StackFrame frame = new StackFrame(1);
            //var method = frame.GetMethod();
            Type type = page.GetType();
            string dir = GetAssemblyDirectory(type);
            _speaker.VoiceDirectory = $"{dir}\\Voice\\{page.LanguageCode}";
            _speaker.Add(fileName);
        }

        public static void AddSpeakDoneEvent(QueueSpeakingDoneEventHandler done)
        {
            _speaker.QueueSpeakingDone += done;
        }

        /// <summary>
        /// 中止播放语音
        /// </summary>
        public static void AbortSpeak()
        {
            _speaker.RemoveSpeakingDoneEvent();
            if(_speaker.IsSpeaking)
            {
                _speaker.Abort();
            }          
        }

        #endregion
    }
}
